﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BrowsersHelper.cs" company="">
//   
// </copyright>
// <summary>
//   The browsers helper.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace UITest.CUIT.CuitControls.Helper
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;

    using Microsoft.VisualStudio.TestTools.UITesting;

    using UITest.Report;

    /// <summary>
    /// The browsers helper.
    /// </summary>
    public class BrowsersHelper
    {
        #region Fields

        private BrowserWindow browser;

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The browser clear cache and cookies.
        /// </summary>
        /// <param name="browsers">
        /// The browser.
        /// </param>
        public void BrowserClearCacheAndCookies(Browsers browsers)
        {
            BrowserWindow.CurrentBrowser = browsers.ToString();
            BrowserWindow.ClearCache();
            BrowserWindow.ClearCookies();
        }

        /// <summary>
        ///     The browser list to string.
        /// </summary>
        /// <returns>
        ///     The <see cref="string" />.
        /// </returns>
        public string BrowserListToString()
        {
            List<BrowserWindow> brws = this.GetBrowserList();
            var sb = new StringBuilder();
            sb.AppendLine("## Browser windows == start");
            foreach (BrowserWindow br in brws)
            {
                sb.AppendLine(br.Name);
            }

            sb.AppendLine("## Browser windows == end");
            return sb.ToString();
        }

        /// <summary>
        ///     The get browser list.
        /// </summary>
        /// <returns>
        ///     The <see cref="List" />.
        /// </returns>
        public List<BrowserWindow> GetBrowserList()
        {
            var windows = new List<BrowserWindow>();
            UITestControlCollection brs = new BrowserWindow().FindMatchingControls();
            foreach (UITestControl br in brs)
            {
                windows.Add(br as BrowserWindow);
            }

            return windows;
        }

        /// <summary>
        /// The kill browser process.
        /// </summary>
        /// <param name="browsers">
        /// The o browser.
        /// </param>
        public void KillBrowserProcess(Browsers browsers)
        {
            IEnumerable<Process> processes = Process.GetProcesses().Where(x => x.ProcessName == browsers.ToString());

            foreach (Process process in processes)
            {
                try
                {
                    if (!process.HasExited)
                    {
                        process.Kill();
                    }
                }
                    
                    // ReSharper disable once EmptyGeneralCatchClause
                catch (Exception)
                {
                }
            }
        }

        /// <summary>
        /// The locate.
        /// </summary>
        /// <param name="searchProperty">
        /// The search property.
        /// </param>
        /// <param name="browserWindow">
        /// The browser window.
        /// </param>
        /// <param name="browsers">
        /// The browsers.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        /// <exception cref="Exception">
        /// </exception>
        public bool Locate(
            string searchProperty, 
            out BrowserWindow browserWindow, 
            Browsers browsers = Browsers.iexplore)
        {
            string compareOperator = "=";

            // If split on '=' does not work, then try '~'
            // Split at the first instance of '='. Other instances are considered part of the value.
            string[] arrayKeyVal = searchProperty.Split(new[] { '=' }, 2);
            if (arrayKeyVal.Length != 2)
            {
                // Otherwise try to split on '~'. If it works then compare type is Contains
                // Split at the first instance of '~'. Other instances are considered part of the value.
                arrayKeyVal = searchProperty.Split(new[] { '~' }, 2);
                if (arrayKeyVal.Length == 2)
                {
                    compareOperator = "~";
                }
                else
                {
                    throw new Exception("Invalid Format");
                }
            }

            // Find the first property in the list of known values
            string searchPropertyName = arrayKeyVal[0];

            // Only IE works
            if (browsers.Equals(Browsers.iexplore))
            {
                // Found the Browsers
                UITestControlCollection brs = new BrowserWindow().FindMatchingControls();
                foreach (UITestControl uiTestControl in brs)
                {
                    var br = (BrowserWindow)uiTestControl;
                    if (searchPropertyName.Equals("Title"))
                    {
                        if (compareOperator.Equals("="))
                        {
                            if (br.Name.Equals(arrayKeyVal[1]))
                            {
                                browserWindow = br;
                                browserWindow.SetFocus();
                                return true;
                            }
                        }
                        else
                        {
                            if (br.Name.Contains(arrayKeyVal[1]))
                            {
                                browserWindow = br;
                                browserWindow.SetFocus();
                                return true;
                            }
                        }
                    }
                    else if (searchPropertyName.Equals("Uri"))
                    {
                        if (compareOperator.Equals("="))
                        {
                            if (br.Uri.AbsoluteUri.Equals(arrayKeyVal[1]))
                            {
                                browserWindow = br;
                                browserWindow.SetFocus();
                                return true;
                            }
                        }
                        else
                        {
                            if (br.Uri.AbsoluteUri.Contains(arrayKeyVal[1]))
                            {
                                browserWindow = br;
                                browserWindow.SetFocus();
                                return true;
                            }
                        }
                    }
                }
            }
            else
            {
                throw new Exception("Non IE Browser Not supported by Microsoft");
            }

            browserWindow = null;
            return false;
        }

        /// <summary>
        /// The locate title contain.
        /// </summary>
        /// <param name="title">
        /// The title.
        /// </param>
        /// <param name="browsers">
        /// The browsers.
        /// </param>
        /// <param name="timeToWait">
        /// The time to wait.
        /// </param>
        /// <returns>
        /// The <see cref="BrowserWindow"/>.
        /// </returns>
        /// <exception cref="Exception">
        /// </exception>
        public BrowserWindow LocateTitleContain(
            string title, 
            Browsers browsers = Browsers.iexplore, 
            int timeToWait = 10000)
        {
            BrowserWindow brw = null;
            if (UITestControl.WaitForCondition(title, x => this.Locate("Title~" + title, out brw, browsers), timeToWait))
            {
                return brw;
            }

            throw new Exception(string.Format("Browser window with title '{0}' is not found", title));
        }

        /// <summary>
        /// The locate title equal.
        /// </summary>
        /// <param name="title">
        /// The title.
        /// </param>
        /// <param name="browsers">
        /// The browsers.
        /// </param>
        /// <param name="timeToWait">
        /// The time to wait.
        /// </param>
        /// <returns>
        /// The <see cref="BrowserWindow"/>.
        /// </returns>
        /// <exception cref="Exception">
        /// </exception>
        public BrowserWindow LocateTitleEqual(
            string title, 
            Browsers browsers = Browsers.iexplore, 
            int timeToWait = 10000)
        {
            BrowserWindow brw = null;
            if (UITestControl.WaitForCondition(title, x => this.Locate("Title=" + title, out brw, browsers), timeToWait))
            {
                return brw;
            }

            throw new Exception(string.Format("Browser window with title '{0}' is not found", title));
        }

        /// <summary>
        /// The locate uri contain.
        /// </summary>
        /// <param name="uri">
        /// The uri.
        /// </param>
        /// <param name="browsers">
        /// The browsers.
        /// </param>
        /// <param name="timeToWait">
        /// The time to wait.
        /// </param>
        /// <returns>
        /// The <see cref="BrowserWindow"/>.
        /// </returns>
        /// <exception cref="Exception">
        /// </exception>
        public BrowserWindow LocateUriContain(string uri, Browsers browsers = Browsers.iexplore, int timeToWait = 10000)
        {
            BrowserWindow brw = null;
            if (UITestControl.WaitForCondition(uri, x => this.Locate("Uri~" + uri, out brw, browsers), timeToWait))
            {
                return brw;
            }

            throw new Exception(string.Format("Browser window with Uri '{0}' is not found", uri));
        }

        /// <summary>
        /// The single browser.
        /// </summary>
        /// <param name="single">
        /// The single.
        /// </param>
        public void SingleBrowser(BrowserWindow single)
        {
            single.SetFocus();
            string title = single.Name;
            List<BrowserWindow> brws = this.GetBrowserList();
            foreach (BrowserWindow br in brws)
            {
                if (!title.Equals(br.Name))
                {
                    br.SetFocus();
                    br.Close();
                }
            }

            single.SetFocus();
        }

        /// <summary>
        /// The start browser.
        /// </summary>
        /// <param name="browsers">
        /// The browser.
        /// </param>
        /// <param name="uri">
        /// The uri.
        /// </param>
        /// <returns>
        /// The <see cref="BrowserWindow"/>.
        /// </returns>
        public BrowserWindow StartBrowser(Browsers browsers, string uri)
        {
            BrowserWindow.CurrentBrowser = browsers.ToString();
            this.browser = BrowserWindow.Launch(new Uri(uri));
            this.browser.Maximized = true;
            ReportListener report = ReportFactory.GetReportListener();
            report.WriteTestOutput(browsers + " : " + uri);
            return this.browser;
        }

        #endregion
    }
}